//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
// Portions Copyright (c) MiTAC Corp. All rights reserved.
//
// File:    sermddMain.c
// Programmer:   Visual.Wei
// Date: 2007-4
// Description: USB serial MDD layer for bootloader,link with PDD
//
#include <windows.h>
#include <usbfn.h>
#include <oal_log.h>
#include <ipl_core.h>

#if 1
#define USB_Unlock() _enable_irq()
#define USB_Lock() _disable_irq()
#else
#define USB_Unlock()
#define USB_Lock()
#endif
#undef OAL_ERROR 
#undef OAL_FUNC
#define OAL_ERROR 1
#define OAL_FUNC 0

//Max packet size
#define EP0MaxSize 		64
#define EPMaxSize 		512
//OEM string,UNICODE is a must
#define MANUFACTURER    L"MiTAC International Corporation"
#define PRODUCT         L"Windows Mobile based device"
#define SERIALNUMBER L"56697375616C2E576569"
static const UCHAR g_SupportedLanguage[] =
{
        0x04,
        USB_STRING_DESCRIPTOR_TYPE,
        0x09, 0x04          //  US English only..
};

typedef struct {
    UCHAR   ucbLength;
    UCHAR   ucbDescriptorType;
    TCHAR   ptcbString[];
} USB_STRING;

static const USB_STRING g_Manufacturer =
{
        sizeof(MANUFACTURER) + 2,
        USB_STRING_DESCRIPTOR_TYPE,
        MANUFACTURER
};

static const USB_STRING g_Product =
{
        sizeof(PRODUCT) + 2,
        USB_STRING_DESCRIPTOR_TYPE,
        PRODUCT
};

static USB_STRING g_SerialNumber=
{
        sizeof(SERIALNUMBER) + 2,
        USB_STRING_DESCRIPTOR_TYPE,
        SERIALNUMBER
};	

//USB Device_Qualifier Descriptor , for high speed device
static const UCHAR g_pucUSBQualifier[] =
{
        ////////////////////////////////////////////////////////////////////////////
        // Device Qualifier Descriptor
        //
        /* 0  */    0x0a,                            //  bLength = 10 bytes.
        /* 1  */    USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE,    //  bDescriptorType 
        /* 2  */    0x10,    0x01,                    //  bcdUSB          = 1.1
        /* 4  */    0x02,                          //  bDeviceClass    = Communication Device Class
        /* 5  */    0x00,                          //  bDeviceSubClass = Unused at this time.
        /* 6  */    0x00,                          //  bDeviceProtocol = Unused at this time.
        /* 7  */    64,                    //  bMaxPacketSize0 = EP0 buffer size..
        /* 8  */    0x01,                          //  bNumConfigs     = 1
        /* 9  */    0x00,                          //  reserved
};
//USB Other_Speed_Configuration Descriptor ,for high speed device
static const UCHAR g_pucUSBOtherQualifier[] =
{
        ////////////////////////////////////////////////////////////////////////////
        // Other Speed Qualifier Descriptor
        //
        /* 0  */    0x09,                            //  bLength = 9 bytes.
        /* 1  */    USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE,    //  bDescriptorType 
        /* 2  */    0x27,    0x00,                    //  WTotalLength=9+9+7*3
        /* 4  */    0x01,                          //  bNumInterfaces     = 1
        /* 5  */    0x02,                          //  bConfigurationValue=2
        /* 6  */    0x00,                          //  iConfiguration=0
        /* 7  */    0x80,                    //  bmAttributes=0x80,bus-powered,D7=1
        /* 8  */    0x64,                          //  MaxPower=100mA
        
        ////////////////////////////////////////////////////////////////////////////
        //  INTERFACE descriptor
        //  have 3 endpoints
        //
        /* 9 */    9,                             //  bLength         = 9 bytes.
        /* 10 */    USB_INTERFACE_DESCRIPTOR_TYPE,    //  bDescriptorType = INTERFACE
        /* 11 */    0x00,                          //  bInterfaceNo    = 0
        /* 12 */    0x00,                          //  bAlternateSet   = 0
        /* 13 */    0x03,                          //  bNumEndPoints   = 3
        /* 14 */    0xff,                          //  bInterfaceClass = Comm if class 
        /* 15 */    0xff,                          //  bIfSubClass     = Comm if sub        (ditto)
        /* 16 */    0xff,                          //  bIfProtocol     = Vendor specific    (ditto)
        /* 17 */    0x00,                          //  iInterface      = unused.

        ////////////////////////////////////////////////////////////////////////////
        //  Endpoint descriptors
        //
        /* 18 */    7,                     //  bLength         = 7 bytes.
        /* 19 */    USB_ENDPOINT_DESCRIPTOR_TYPE,    //  bDescriptorType = ENDPOINT[IN]
        /* 20 */    0x81,                  //  bEndpointAddr   = IN - EP1
        /* 21 */    0x02,                  //  bmAttributes    = BULK
        /* 22 */    0x40,    0x0,       //  wMaxPacketSize
        /* 23 */    0,                     //  bInterval       = ignored for BULK.

        /* 24 */    7,                     //  bLength         = 7 bytes.
        /* 25 */    USB_ENDPOINT_DESCRIPTOR_TYPE,    //  bDescriptorType = ENDPOINT [OUT]
        /* 26 */    0x02,                  //  bEndpointAddr   = OUT -- EP2
        /* 27 */    0x02,                  //  bmAttributes    = BULK
        /* 28 */    0x40,    0x0,       //  wMaxPacketSize
        /* 29 */    0,                     //  bInterval       = ignored for BULK.

        /* 30 */    7,                     //  bLength         = 7 bytes.
        /* 31 */    USB_ENDPOINT_DESCRIPTOR_TYPE,    //  bDescriptorType = ENDPOINT [IN]
        /* 32 */    0x83,                  //  bEndpointAddr   = IN -- EP3
        /* 33 */    0x03,                  //  bmAttributes    = Interrupt endpoint.
        /* 34 */    8,    0x00,       //  wMaxPacketSize
        /* 35 */    80                   //  bInterval       = 1 ms polling from host.        
};

//USB descriptors
static const UCHAR g_pucUSBDescriptors[] =
{
        ////////////////////////////////////////////////////////////////////////////
        // Device Descriptor
        //
        /* 0  */    18,                            //  bLength = 18 bytes.
        /* 1  */    USB_DEVICE_DESCRIPTOR_TYPE,    //  bDescriptorType = DEVICE
        /* 2  */    0x00,    0x02,                    //  bcdUSB          = 2.0
        /* 4  */    0x02,                          //  bDeviceClass    = Communication Device Class
        /* 5  */    0x00,                          //  bDeviceSubClass = Unused at this time.
        /* 6  */    0x00,                          //  bDeviceProtocol = Unused at this time.
        /* 7  */    64,                    //  bMaxPacketSize0 = EP0 buffer size..
        /* 8  */    0x40,    0x33,                    //  idVendor        = Mitac ID.
        /* 10*/    0x3A,    0x04,                    //  idProduct       =  Product ID.
        /* 12*/    0x01,    0x00,                    //  bcdDevice       = 0.1
        /* 14*/    0x01,                          //  iManufacturer   = OEM should fill this..
        /* 15*/    0x02,                          //  iProduct        = OEM should fill this..
        /* 16*/    0x03,                          //  iSerialNumber   = OEM should fill this..
        /* 17*/    0x01,                          //  bNumConfigs     = 1

        ////////////////////////////////////////////////////////////////////////////
        // configuration descriptor
        // have 1 interface
        //
        /* 18 */    9,                                     //  bLength         = 9 bytes.
        /* 19 */    USB_CONFIGURATION_DESCRIPTOR_TYPE,     //  bDescriptorType = CONFIGURATION
        /* 20 */    0x27,    0x00,                    //  wTotalLength    = 9+9+7*3
        /* 22 */    0x01,                          //  bNumInterfaces  = 1 .
        /* 23 */    0x01,                          //  bConfValue      = 1
        /* 24 */    0x00,                          //  iConfiguration  = unused.
        /* 25 */    0x80,                          //  bmAttributes    = bus-Powered.D7==1
        /* 26 */    0xC8,                          //  MaxPower        = 200mA

        ////////////////////////////////////////////////////////////////////////////
        //  INTERFACE descriptor
        //  have 3 endpoints
        //
        /* 27 */    9,                             //  bLength         = 9 bytes.
        /* 28 */    USB_INTERFACE_DESCRIPTOR_TYPE,    //  bDescriptorType = INTERFACE
        /* 29 */    0x00,                          //  bInterfaceNo    = 0
        /* 30 */    0x00,                          //  bAlternateSet   = 0
        /* 31 */    0x03,                          //  bNumEndPoints   = 3
        /* 32 */    0xff,                          //  bInterfaceClass = Comm if class 
        /* 33 */    0xff,                          //  bIfSubClass     = Comm if sub        (ditto)
        /* 34 */    0xff,                          //  bIfProtocol     = Vendor specific    (ditto)
        /* 35 */    0x00,                          //  iInterface      = unused.

        ////////////////////////////////////////////////////////////////////////////
        //  Endpoint descriptors
        //
        /* 36 */    7,                     //  bLength         = 7 bytes.
        /* 37 */    USB_ENDPOINT_DESCRIPTOR_TYPE,    //  bDescriptorType = ENDPOINT[IN]
        /* 38 */    0x81,                  //  bEndpointAddr   = IN - EP1
        /* 39 */    0x02,                  //  bmAttributes    = BULK
        /* 40 */    00,    0x02,       //  wMaxPacketSize
        /* 41 */    0,                     //  bInterval       = ignored for BULK.

        /* 42 */    7,                     //  bLength         = 7 bytes.
        /* 43 */    USB_ENDPOINT_DESCRIPTOR_TYPE,    //  bDescriptorType = ENDPOINT [OUT]
        /* 44 */    0x02,                  //  bEndpointAddr   = OUT -- EP2
        /* 45 */    0x02,                  //  bmAttributes    = BULK
        /* 46 */    0,    0x02,       //  wMaxPacketSize
        /* 47 */    0,                     //  bInterval       = ignored for BULK.

        /* 48 */    7,                     //  bLength         = 7 bytes.
        /* 49 */    USB_ENDPOINT_DESCRIPTOR_TYPE,    //  bDescriptorType = ENDPOINT [IN]
        /* 50 */    0x83,                  //  bEndpointAddr   = IN -- EP3
        /* 51 */    0x03,                  //  bmAttributes    = Interrupt endpoint.
        /* 52 */    8,    0x00,       //  wMaxPacketSize
        /* 53 */    8                   //  bInterval       = 1 ms polling from host.
} ;


UFN_MDD_INTERFACE_INFO g_mdd;
UFN_PDD_INTERFACE_INFO g_pdd;

static UCHAR g_requestbuf[2];
	
typedef enum {
    EP0Setup = 0,
    EP0Out,
    EP0In
} EP0_DIR;

typedef struct _EP0_REQUEST
{
    EP0_DIR eDir;
    UCHAR *pucData;
    DWORD dwExpectedSize;
    DWORD dwActualSize;
}EP0_REQUEST, *PEP0_REQUEST;

enum DEVICE_STATE {
    DS_DETACHED = 0,
    DS_ATTACHED,
    DS_POWERED,
    DS_DEFAULT,
    DS_ADDRESSED,
    DS_CONFIGURED,
    DS_SUSPENDED,
};

enum TRANSFER_STATE {
    TS_IDLE=0,
    TS_RECEIVING_MESSAGE,
    TS_SENDING_MESSAGE,
    TS_RECEIVING_PACKET,
    TS_SENDING_PACKET,
};

typedef struct _pipe_trans
{
	UCHAR data[512*4];
	DWORD maxsize;
	UCHAR * start;
	DWORD validlen;
}PIPE_TRANS;

typedef struct {
	UFN_BUS_SPEED speed;
	enum DEVICE_STATE devState;
	EP0_REQUEST EP0Req;
	STransfer EP0Trans; // EP0
	STransfer EP1Trans; // Bulk in
	STransfer EP2Trans; // Bulk out
	STransfer EP3Trans; // Int in
	enum TRANSFER_STATE EP0State ;// TS_IDLE;
	enum TRANSFER_STATE EP1State ;// TS_IDLE;
	enum TRANSFER_STATE EP2State ;// TS_IDLE;
	enum TRANSFER_STATE EP3State ;// TS_IDLE;
	PIPE_TRANS EP2pipe;
	UCHAR EP0Maxsize; //max packet size
	USHORT EP1Maxsize;//max packet size
	USHORT EP2Maxsize;//max packet size
	USHORT EP3Maxsize;//max packet size
} SERIAL_DEV, *PSERIAL_DEV;

static SERIAL_DEV g_SerUSBDev;

static void PipeTrans_CompleteTransfer(STransfer * );
static  BOOL PipeTrans_Init(DWORD);

static void SetDeviceDescriptor(USB_DEVICE_DESCRIPTOR * desc,USB_ENDPOINT_DESCRIPTOR * enddesc)
{
	PSERIAL_DEV dev=&g_SerUSBDev;
	if(dev->speed==BS_HIGH_SPEED)
	{
		//USB2.0
		desc->bcdUSB=0x0200;
		desc->bMaxPacketSize0=USB_HIGH_SPEED_CONTROL_MAX_PACKET_SIZE;
		enddesc->wMaxPacketSize=USB_HIGH_SPEED_BULK_MAX_PACKET_SIZE;
		(enddesc+1)->wMaxPacketSize=USB_HIGH_SPEED_BULK_MAX_PACKET_SIZE;
		(enddesc+2)->wMaxPacketSize=USB_HIGH_SPEED_INTERRUPT_MAX_PACKET_SIZE;
	}else
	{
		//USB1.1
		desc->bcdUSB=0x0110;
		desc->bMaxPacketSize0=USB_FULL_SPEED_CONTROL_MAX_PACKET_SIZE;
		enddesc->wMaxPacketSize=USB_FULL_SPEED_BULK_MAX_PACKET_SIZE;
		(enddesc+1)->wMaxPacketSize=USB_FULL_SPEED_BULK_MAX_PACKET_SIZE;
		(enddesc+2)->wMaxPacketSize=USB_FULL_SPEED_INTERRUPT_MAX_PACKET_SIZE;
	}
}


static BOOL DoVendorCommand(USB_DEVICE_REQUEST *pUdr, EP0_REQUEST *pRequest)
{
	BOOL fRet = TRUE;

	switch (pUdr->bRequest)
	{
		case 0x22:
			OALMSG(1,(L"SET_CONTROL_LINE_STATE %X\r\n",pUdr->wValue));
			fRet = FALSE;
			break;

	default:
		fRet = FALSE;
		break;
	}
	return fRet;
}


static BOOL GetDescriptor(USB_DEVICE_REQUEST *pUdr, EP0_REQUEST *pRequest)
{
	UCHAR *pucData;
	WORD wLength;
	WORD wType = pUdr->wValue;
	BOOL fRet = TRUE;

	switch (HIBYTE(wType))
	{
	case USB_DEVICE_DESCRIPTOR_TYPE:
		pucData = (UCHAR *)g_pucUSBDescriptors;
		wLength = g_pucUSBDescriptors[0];
		break;

	case USB_CONFIGURATION_DESCRIPTOR_TYPE:
		pucData = (UCHAR *) (g_pucUSBDescriptors+18);
		wLength = sizeof(g_pucUSBDescriptors)-g_pucUSBDescriptors[0];
		break;
	case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE:
		pucData = (UCHAR *)g_pucUSBQualifier;
		wLength = g_pucUSBQualifier[0];
		break;
	case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE:
		pucData = (UCHAR *)g_pucUSBOtherQualifier;
		wLength =sizeof(g_pucUSBOtherQualifier);
		break;		
	case USB_STRING_DESCRIPTOR_TYPE:
		switch (LOBYTE(wType))
		{
		case 0x00:
			pucData = (UCHAR *)g_SupportedLanguage;
			wLength = g_SupportedLanguage[0];
			break;

		case 0x01:
			pucData = (UCHAR *) & g_Manufacturer;
			wLength = g_Manufacturer.ucbLength;
			break;

		case 0x02:
			pucData = (UCHAR *) & g_Product;
			wLength = g_Product.ucbLength;
			break;

		case 0x03:
			pucData = (UCHAR *) & g_SerialNumber;
			wLength = g_SerialNumber.ucbLength;
			break;

		default:
			OALMSG(OAL_ERROR, (L"*** Unknown STRING index %d\r\n", LOBYTE(wType)));
			fRet = FALSE;
			break;
		}
		break;

	default:
		OALMSG(OAL_ERROR, (L"*** Unknown GET_DESCRIPTOR request:0x%x\r\n", HIBYTE(wType)));
		fRet = FALSE;
		break;
	}

	if (fRet)
	{
		pRequest->eDir = EP0In;
		pRequest->pucData = pucData;
		pRequest->dwExpectedSize = pUdr->wLength;
		pRequest->dwActualSize = min(wLength, pUdr->wLength);
	}
	return fRet;
}


static BOOL HandleSetupPacket(USB_DEVICE_REQUEST *pUdr, EP0_REQUEST *pRequest)
{
	if (pUdr->bmRequestType & (USB_REQUEST_CLASS | USB_REQUEST_VENDOR))
	{
		if (!DoVendorCommand(pUdr, pRequest))
		{
			OALMSG(OAL_ERROR, (L"**** Unhandled verndor command 0x%x\r\n", pUdr->bRequest));
			pRequest->eDir = EP0Setup;
			pRequest->pucData = NULL;
			pRequest->dwExpectedSize = 0;
			pRequest->dwActualSize = 0;
		}
		return TRUE;
	}

	// standard request
	pRequest->eDir = EP0Setup;
	pRequest->pucData = NULL;
	pRequest->dwExpectedSize = 0;
	pRequest->dwActualSize = 0;

	switch (pUdr->bRequest)
	{
	case USB_REQUEST_GET_STATUS:
		//it is rarely used
		if (pUdr->bmRequestType |USB_REQUEST_DEVICE_TO_HOST)
		{
			if(pUdr->bmRequestType |USB_REQUEST_FOR_ENDPOINT)
			{
				if((pUdr->wIndex!=0)&&(pUdr->wIndex!=0x81)
					&&(pUdr->wIndex!=2)&&(pUdr->wIndex!=0x83))
					g_pdd.pfnStallEndpoint(g_pdd.pvPddContext,0);
			}
			*(WORD *)g_requestbuf=0;
			pRequest->eDir = EP0In;
			pRequest->pucData =(UCHAR *)g_requestbuf;
			pRequest->dwExpectedSize = pUdr->wLength;
			pRequest->dwActualSize = min(2, pUdr->wLength);
			OALMSG(OAL_WARN, (L"***GET_STATE Request\r\n"));
		}
		break;

	case USB_REQUEST_CLEAR_FEATURE:
		if (pUdr->bmRequestType == 0x02)
		{
			OALMSG(OAL_WARN, (L"***Endpoint Request\r\n"));
		}
		break;

	case USB_REQUEST_SET_FEATURE:
		if (pUdr->bmRequestType == 0x02)
		{
			OALMSG(OAL_WARN, (L"***Endpoint Request\r\n"));
		}
		break;

	case USB_REQUEST_SET_ADDRESS:
		g_pdd.pfnSetAddress( g_pdd.pvPddContext, (BYTE)pUdr->wValue);
		//g_SerUSBDev.devState=DS_ADDRESSED;
		g_mdd.pfnNotify(NULL,UFN_MSG_SET_ADDRESS,pUdr->wValue);
		break;

	case USB_REQUEST_GET_DESCRIPTOR:
		if (!GetDescriptor(pUdr, pRequest))
		{
			OALMSG(OAL_ERROR, (L"*** UnHandled GET_DESCRIPTOR request:0x%x\r\n",pUdr->wValue));
		}
		break;

	case USB_REQUEST_SET_DESCRIPTOR:
		// add a new descriptor
	case USB_REQUEST_GET_CONFIGURATION:
		//need 1 byte data stage,rarely used
		if(g_SerUSBDev.devState!=DS_CONFIGURED)
			*g_requestbuf=0;
		else
			*g_requestbuf=1;
		pRequest->eDir = EP0In;
		pRequest->pucData =(UCHAR *)g_requestbuf;
		pRequest->dwExpectedSize = pUdr->wLength;
		pRequest->dwActualSize = min(1, pUdr->wLength);
		OALMSG(OAL_WARN, (L"***GET_CONFIGURATION Request\r\n"));
		break;

	case USB_REQUEST_SET_CONFIGURATION:
		OALMSG(1, (L"set_configuration\r\n"));
		//printk(L"set_configuration\r\n");
		if(pUdr->wValue==1)
			g_mdd.pfnNotify(NULL,UFN_MSG_CONFIGURED,pUdr->wValue);
		else if(pUdr->wValue==0)
			g_mdd.pfnNotify(NULL,UFN_MSG_SET_ADDRESS,pUdr->wValue);
		break;

	case USB_REQUEST_GET_INTERFACE:
		//need 1 byte data stage,rarely used
		*g_requestbuf=0;
		pRequest->eDir = EP0In;
		pRequest->pucData =(UCHAR *)g_requestbuf;
		pRequest->dwExpectedSize = pUdr->wLength;
		pRequest->dwActualSize = min(1, pUdr->wLength);
		OALMSG(OAL_WARN, (L"***GET_INTERFACE Request\r\n"));
		break;
	case USB_REQUEST_SET_INTERFACE:
	case USB_REQUEST_SYNC_FRAME:
		//need 2 byte data stage,rarely used
		break;

	default:
		OALMSG(OAL_WARN, (L"*** Unknown request 0x%x\r\n", pUdr->bRequest));
	}
	return TRUE;
}

// transmit transfer on EP1 (BULK IN)
static VOID IssueEP1Transfer(PVOID buf,DWORD size)
{
	STransfer *ptrans=&g_SerUSBDev.EP1Trans;
	if (g_SerUSBDev.EP1State!= TS_SENDING_PACKET)
	{
		g_SerUSBDev.EP1State = TS_SENDING_PACKET;
		//printk(L"issue trans 0x%x\r\n",&(g_SerUSBDev.EP1State));
		ptrans->pvBuffer = buf;
		ptrans->cbBuffer = size;
		ptrans->cbTransferred = 0;
		ptrans->dwUsbError = UFN_NOT_COMPLETE_ERROR; // Possible values are in usbfntypes.h
		ptrans->pvPddData = NULL;
		ptrans->pvPddTransferInfo = NULL;
		ptrans->dwFlags = USB_IN_TRANSFER;
		g_pdd.pfnIssueTransfer( g_pdd.pvPddContext, 1, ptrans );
	}
}
// receive transfer on EP2 (BULK OUT)
static VOID IssueEP2Transfer(PVOID buf,DWORD size)
{
	STransfer *ptrans=&g_SerUSBDev.EP2Trans;
	if (g_SerUSBDev.EP2State!= TS_RECEIVING_PACKET)
	{
		g_SerUSBDev.EP2State = TS_RECEIVING_PACKET;
		//printk(L"issue trans 0x%x\r\n",&(g_SerUSBDev.EP2State));
		ptrans->pvBuffer = buf;
		ptrans->cbBuffer = size;
		ptrans->cbTransferred = 0;
		ptrans->dwUsbError = UFN_NOT_COMPLETE_ERROR; // Possible values are in usbfntypes.h
		ptrans->pvPddData = NULL;
		ptrans->pvPddTransferInfo = NULL;
		ptrans->dwFlags = USB_OUT_TRANSFER;
		g_pdd.pfnIssueTransfer( g_pdd.pvPddContext, 2, ptrans );
	}
}

static BOOL WINAPI NotifyHandler (PVOID pvMddContext,DWORD dwMsg,DWORD dwParam)
{
	USB_DEVICE_REQUEST request;
	STransfer *pTransfer;
	volatile PSERIAL_DEV dev=&g_SerUSBDev;

	switch ( dwMsg )
	{
	case UFN_MSG_SETUP_PACKET:
		request = *(USB_DEVICE_REQUEST*)(void*)dwParam;

		OALMSG(OAL_FUNC, (L"Got SETUP < %x %x %x %x %x> packet.\r\n",
			           request.bmRequestType, request.bRequest, request.wValue, request.wIndex,request.wLength));

		if ( !HandleSetupPacket(&request, &dev->EP0Req) )
		{
			OALMSG(OAL_ERROR, (L"ERROR PARSING SETUP PACKET\r\n"));
		}

		if (dev->EP0Req.eDir != EP0Setup)
		{
			//EP0 control message,need data stage
			dev->EP0Trans.pvBuffer = dev->EP0Req.pucData;
			dev->EP0Trans.cbBuffer = dev->EP0Req.dwActualSize;
			dev->EP0Trans.cbTransferred = 0;
			dev->EP0Trans.dwUsbError = UFN_NOT_COMPLETE_ERROR; 
			dev->EP0Trans.pvPddData = NULL;
			dev->EP0Trans.pvPddTransferInfo = NULL;

			if (dev->EP0Req.eDir == EP0In)
			{
				OALMSG(OAL_FUNC, (L"Got SETUP IN packet\r\n"));
				dev->EP0Trans.dwFlags = USB_REQUEST_DEVICE_TO_HOST;
				dev->EP0State = TS_SENDING_MESSAGE;
			}
			else
			{
				OALMSG(OAL_FUNC, (L"Got SETUP OUT packet.\r\n"));
				dev->EP0Trans.dwFlags = USB_REQUEST_HOST_TO_DEVICE;
				dev->EP0State = TS_RECEIVING_MESSAGE;
			}
			g_pdd.pfnIssueTransfer( g_pdd.pvPddContext, 0, &dev->EP0Trans );
		}
		else
		{
			//EP0,no data control message,status stage
			OALMSG(OAL_FUNC, (L"Got SETUP <NO DATA: %x %x %x %x %x> packet.\r\n",
			           request.bmRequestType, request.bRequest, request.wValue, request.wIndex,request.wLength));

			dev->EP0State = TS_IDLE;
			g_pdd.pfnSendControlStatusHandshake( g_pdd.pvPddContext, 0 );
		}
		break;

	case UFN_MSG_TRANSFER_COMPLETE:
		//EP0 control message,status stage
		pTransfer = (STransfer *)dwParam;
		if ( pTransfer == &dev->EP0Trans )
		{
			switch ( dev->EP0State )
			{
			case TS_RECEIVING_MESSAGE:
				dev->EP0State = TS_IDLE;
				OALMSG(OAL_FUNC, (L"Done receiving data.\r\n"));
				g_pdd.pfnSendControlStatusHandshake( g_pdd.pvPddContext, 0 );

				memset(&dev->EP0Req, 0, sizeof (dev->EP0Req));
				break;
			case TS_SENDING_MESSAGE:
				OALMSG(OAL_FUNC, (L"Done sending data.\r\n"));

				dev->EP0State = TS_IDLE;
				g_pdd.pfnSendControlStatusHandshake( g_pdd.pvPddContext, 0 );
				memset(&dev->EP0Req, 0, sizeof (dev->EP0Req));
				break;
			}
		}
		else if ( pTransfer == &dev->EP2Trans )
		{
			//RX, BULK OUT data received on EP1
			//OALMSG(OAL_FUNC, (L"Received a packet [%d bytes]!\r\n", pTransfer->cbTransferred ));
			//printk(L"Rx a packet [%d bytes] 0x%x!\r\n", pTransfer->cbTransferred,&(dev->EP2State));
			PipeTrans_CompleteTransfer(pTransfer);

			dev->EP2State= TS_IDLE;

		}
		else if ( pTransfer == &dev->EP1Trans )
		{
			//TX
			if ( dev->EP1State == TS_SENDING_PACKET )
			{	
				dev->EP1State = TS_IDLE;
				OALMSG(OAL_FUNC, (L"EP1 transfer complete!\r\n"));
			}
			else
			{
				OALMSG(OAL_ERROR, (L"Unexpected EP1 transfer state!"));
			}
			memset(&dev->EP1Trans,0,sizeof(STransfer));
			dev->EP1State = TS_IDLE;
		}
		else if ( pTransfer == &dev->EP3Trans )
		{
			//RX interrupt End point
			OALMSG(OAL_FUNC, ( L"EP3 Interrupt successfully sent!\r\n"));
		}
		else
		{
			OALMSG(OAL_ERROR, (L"INVALID  TRANSFER!\r\n"));
		}
		break;

	case UFN_MSG_BUS_EVENTS:
		switch ( dwParam )
		{
		case UFN_DETACH:
			dev->devState = DS_DETACHED;
			break;
		case UFN_ATTACH:
			dev->devState = DS_ATTACHED;
			break;
		case UFN_RESET:
			dev->devState = DS_DEFAULT;
			dev->EP0State = TS_IDLE;
			dev->EP1State = TS_IDLE;
			dev->EP2State = TS_IDLE;
			break;
		case UFN_SUSPEND:
			dev->devState = DS_ATTACHED;
			break;
		case UFN_RESUME:
			dev->devState = DS_ATTACHED;
			break;
		default:
			ASSERT(!"Unexpected bus event!");
		}
		break;

	case UFN_MSG_BUS_SPEED:
		dev->speed = (UFN_BUS_SPEED) dwParam;
		if(dev->speed==BS_HIGH_SPEED)
			OALMSG(OAL_FUNC, ( L"high speed!\r\n"));
		else
			OALMSG(OAL_FUNC, ( L"full speed!\r\n"));
		//SetDeviceDescriptor((USB_DEVICE_DESCRIPTOR *)g_pucUSBDescriptors,
						//	(USB_ENDPOINT_DESCRIPTOR *)(g_pucUSBDescriptors+36));
		break;

	case UFN_MSG_SET_ADDRESS:
		if ( dwParam )
		{
			dev->devState = DS_ADDRESSED;
		}
		else
		{
			dev->devState = DS_DEFAULT;
		}
		break;	
	case UFN_MSG_CONFIGURED:	
		//USB is OK now,EP1,EP2,EP3 can be opened
		dev->devState = DS_CONFIGURED;
		g_pdd.pfnClearEndpointStall(g_pdd.pvPddContext,1);
		g_pdd.pfnClearEndpointStall(g_pdd.pvPddContext,2);
		g_pdd.pfnClearEndpointStall(g_pdd.pvPddContext,3);
		break;
	default:
		ASSERT(!"Unexpected Msg !");
	}

	return FALSE;
}


// register the USB device, setup the non zero endpoints
static void RegisterUSBDevice()
{
	static USB_DEVICE_DESCRIPTOR deviceDescriptor;
	static UFN_ENDPOINT rgEndPoints[3];
	static UFN_INTERFACE Interface;
	static UFN_CONFIGURATION deviceConfiguration;

	deviceConfiguration.pInterfaces = &Interface;
	deviceConfiguration.Descriptor.bNumInterfaces = 1;
	Interface.pEndpoints = rgEndPoints;
	Interface.Descriptor.bNumEndpoints = 3;
	rgEndPoints[0].Descriptor.bEndpointAddress = 0x81; // EP1, IN (BULK)
	rgEndPoints[0].Descriptor.wMaxPacketSize = EPMaxSize;
	rgEndPoints[0].Descriptor.bmAttributes = 0;
	rgEndPoints[1].Descriptor.bEndpointAddress = 0x02; // EP2, OUT (BULK)
	rgEndPoints[1].Descriptor.wMaxPacketSize = EPMaxSize;
	rgEndPoints[1].Descriptor.bmAttributes = 0;
	rgEndPoints[2].Descriptor.bEndpointAddress = 0x83; // EP3, IN (INT)
	rgEndPoints[2].Descriptor.wMaxPacketSize = EPMaxSize;
	rgEndPoints[2].Descriptor.bmAttributes = 0;
	deviceDescriptor.bMaxPacketSize0 = EP0MaxSize;

	g_pdd.pfnRegisterDevice( g_pdd.pvPddContext,NULL, NULL, NULL,
	                                  &deviceDescriptor, &deviceConfiguration, NULL,NULL, 0 );
}


void MDD_Read(PVOID buf,DWORD size);
void MDD_Write(PVOID buf,DWORD size);

void MDD_Deinit()
{
	g_pdd.pfnStop(g_pdd.pvPddContext);
	g_pdd.pfnDeinit(g_pdd.pvPddContext);
}

BOOL MDD_Init()
{
	volatile SERIAL_DEV *dev=&g_SerUSBDev;
	//BYTE buf[200];
	OALMSG(OAL_FUNC, (L"+MDDInit\r\n"));

	g_mdd.dwVersion = 1;
	g_mdd.pfnNotify = NotifyHandler;

	memset( &g_pdd, 0, sizeof(g_pdd) );
	g_pdd.dwVersion = 1;

	//globle 
	g_SerUSBDev.devState = DS_DETACHED;
	g_SerUSBDev.EP0State = TS_IDLE;
	g_SerUSBDev.EP1State = TS_IDLE;
	g_SerUSBDev.EP2State = TS_IDLE;	
	g_SerUSBDev.EP3State = TS_IDLE;

	//init Rx Pipe
	PipeTrans_Init(512);// WCEUSBSH Bug. Only can usb MaxPacketSize
	
	// initialize usb PDD
	if ( UfnPdd_Init( NULL, NULL, &g_mdd, &g_pdd) != ERROR_SUCCESS )
	{
		OALMSG(OAL_ERROR, (L"UfnPdd_Init failed!"));
		return FALSE;
	}

	// register device
	RegisterUSBDevice();

	// attach device to USB bus
	g_pdd.pfnStart( g_pdd.pvPddContext );

	OALMSG(OAL_FUNC, (L"-MDD_Init\r\n"));
#if 0	
	//Visual: for test
	while(1)
	{
		MDD_Read(buf,6);
		printk(L"\r\n0x%x %x %x %x %x %x \r\n",
		buf[0],buf[1],buf[2],buf[3],
		buf[4],buf[5]);
	}
#endif	
	OALMSG(OAL_FUNC, (L"USB wait for ready\r\n"));
	//printk (L"USB wait for ready\r\n");
	//wait for USB ready
	while(dev->devState!=DS_CONFIGURED);
	//{
		//printk (L"USB state %d\r\n",g_SerUSBDev.devState);
	//}
		//InterruptThread( g_pdd.pvPddContext );

	OALMSG(OAL_FUNC, (L"USB is OK now\r\n"));
	printk(L"USB is OK\r\n");
	return TRUE;
}


static  BOOL  PipeTrans_Init(DWORD transize)
{
	PSERIAL_DEV dev=&g_SerUSBDev;
	
	dev->EP2pipe.start=dev->EP2pipe.data;
	dev->EP2pipe.maxsize=transize;		
	dev->EP2pipe.validlen=0;
	return TRUE;

}

static BOOL PipeTrans_IsEmpty()
{
	PSERIAL_DEV dev=&g_SerUSBDev;
	return (dev->EP2pipe.validlen==0);
}

static  void PipeTrans_ReadBuf(UCHAR * buf,DWORD size,DWORD * preadlen)
{
	PSERIAL_DEV dev=&g_SerUSBDev;

	if(size>dev->EP2pipe.validlen)
	{
		memcpy(buf,dev->EP2pipe.start,dev->EP2pipe.validlen);
		*preadlen=dev->EP2pipe.validlen;
		dev->EP2pipe.validlen=0;
	}
	else
	{
		memcpy(buf,dev->EP2pipe.start,size);
		*preadlen=size;
		dev->EP2pipe.validlen-=size;
		dev->EP2pipe.start+=size;
	}		
}

static  void PipeTrans_TxIssueTransfer(PVOID buf,DWORD size)
{
	IssueEP1Transfer(buf,size);
}

static  void PipeTrans_RxIssueTransfer()
{
	PSERIAL_DEV dev=&g_SerUSBDev;
	//clear buffer
	dev->EP2pipe.start=dev->EP2pipe.data;
	dev->EP2pipe.validlen=0;
	IssueEP2Transfer(dev->EP2pipe.data,dev->EP2pipe.maxsize);
	
}

static  void PipeTrans_CompleteTransfer(STransfer * trans)
{
	PSERIAL_DEV dev=&g_SerUSBDev;
	
	if(trans->dwUsbError==UFN_NO_ERROR)
	{
		dev->EP2pipe.validlen=trans->cbTransferred;
	}
	else
		OALMSG(OAL_ERROR, (L"rx transfer error\r\n"));

	//printk(L"pipe buf size:%d\r\n",dev->EP2pipe.validlen);
	//memset(trans,0,sizeof(STransfer));
}

void MDD_Read(PVOID buf,DWORD size)
{
	//Visual : race condition happened here
	volatile PSERIAL_DEV dev=&g_SerUSBDev;
	DWORD reqRemain=size;
	DWORD actualread=0;
	UCHAR * bufptr=buf;

	//printk(L"need %dB",size);		
	while(reqRemain>0)
	{
		USB_Lock();
		if(PipeTrans_IsEmpty())
		{
			PipeTrans_RxIssueTransfer();
			USB_Unlock();
			//polling simulate interrupt
			while(dev->EP2State==TS_RECEIVING_PACKET);
			//OALMSG(OAL_FUNC, (L"wait end\r\n"));
				//terruptThread( g_pdd.pvPddContext );
		}
		else
		{
			PipeTrans_ReadBuf(bufptr,reqRemain,&actualread);
			USB_Unlock();
			//printk(L"need %d act:%d\r\n",reqRemain,actualread);	
			reqRemain-=actualread;
			bufptr+=actualread;
		}
		
	}
	OALMSG(OAL_FUNC, (L"MDD read done\r\n"));
}


void MDD_Write(PVOID buf,DWORD size)
{
	//Visual : race condition happened here
	volatile PSERIAL_DEV dev=&g_SerUSBDev;

	//printk(L"w need %dB",size);		

	USB_Lock();
	PipeTrans_TxIssueTransfer(buf,size);
	USB_Unlock();
	
	//polling simulate interrupt
	while(dev->EP1State==TS_SENDING_PACKET);
	//printk(L"wait end\r\n");
	//terruptThread( g_pdd.pvPddContext );

	OALMSG(OAL_FUNC, (L"MDD write done\r\n"));
}

